// eventCenter 提供如下接口

//   1. register(eventid, target, callback),
//      将callback注册到eventid事件上, 同一target只能对同一eventid注册一个callback, 否则会被忽略.

//   2. unregister(eventid, target)
//      清除target在eventid上的callback.

//   3. unregisterAll(target)

//   4. fire(eventid, ...)
//      派发eventid事件, 调用fire时传的参数(包括eventid这个参数)会转发到该eventid的callback上.
//      派发事件时的回调导致又新注册了回调, 那么新的回调在下次派发该事件时才会生效; 
//      派发过程中如果移除了回调, 不会影响其它回调的调用.

(function () {
    let EventCenter = function () {
        this._handlers = {};
        this._currentEvents = [];
        this._dispatchings = [];
    };

    EventCenter.prototype._exist = function (handlers, target) {
        for (let i = 0; i < handlers.length; i += 2) {
            if (handlers[i] == target) return i;
        }
        return null;
    };

    EventCenter.prototype._removeOne = function (handlers, target) {
        let index = this._exist(handlers, target)

        if (index != null) {
            handlers.splice(index, 2);
            return true;
        } else {
            return false
        }
    };

    /**
     * @param  {} eventid
     * @param  {} target
     * @param  {} callback
     */
    EventCenter.prototype.register = function (eventid, target, callback) {
        if (eventid == null || typeof target !== "object" || typeof callback !== "function") {
            cc.log("[EventCenter] register parameter is invalid. ignore. eventid=", eventid);
            return;
        }

        let handlers = this._handlers[eventid] || [];
        this._handlers[eventid] = handlers;

        if (this._exist(handlers, target) == null) {
            handlers.push(target, callback);
        }
    };

    EventCenter.prototype.unregister = function (eventid, target) {
        if (eventid == null || target == null) {
            cc.log("[EventCenter] unregister a null eventid or target. ignore.");
            return;
        }

        let handlers = this._handlers[eventid];
        if (handlers == null) return;

        if (this._removeOne(handlers, target)) {
            for (let i = 0; i < this._currentEvents.length; ++i) {
                if (eventid == this._currentEvents[i]) {
                    let dispatching = this._dispatchings[i];
                    let index = this._exist(dispatching, target);
                    dispatching[index] = null;
                    dispatching[index + 1] = null;
                }
            }
        }

        if (handlers.length == 0) {
            delete this._handlers[eventid]
        }
    };

    EventCenter.prototype.unregisterAll = function (target) {
        if (target == null) {
            cc.log("[EventCenter] unregister all for a null target. ignore.")
            return;
        }

        for (let eventid in this._handlers) {
            this.unregister(eventid, target);
        }
    };

    EventCenter.prototype.fire = function (eventid) {
        if (eventid == null) {
            cc.log("[EventCenter] fire a null eventid. ignore.");
            return;
        }

        let handlers = this._handlers[eventid];
        if (handlers == null) return;

        this._currentEvents.push(eventid);
        let dispatching = handlers.slice(0);
        this._dispatchings.push(dispatching);

        for (let i = 0; i < dispatching.length; i += 2) {
            let target = dispatching[i];
            let callback = dispatching[i + 1];
            if (target && callback) {
                callback.apply(target, arguments);
            }
        }

        this._currentEvents.pop();
        this._dispatchings.pop();
    };

    module.exports = EventCenter;
})();